﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;

namespace 账号管理
{
    /// <summary>
    /// 数据库访问类
    /// </summary>
    public class XConnection : IDatabase
    {
        /// <summary>
        /// 数据库链接
        /// </summary>
        private readonly string _ConnectionString;
        /// <summary>
        /// 数据库实例
        /// </summary>
        private readonly DbProviderFactory _ProviderFactory;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connectionStringName">数据库链接配置名称</param>
        public XConnection(string connectionStringName)
        {
            var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
            var connectionString = connectionStringSettings.ConnectionString;
            _ConnectionString = connectionString;
            _ProviderFactory = DbProviderFactories.GetFactory(connectionStringSettings.ProviderName);
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connectionString">数据库链接</param>
        /// <param name="providerName">数据库实例</param>
        public XConnection(string connectionString, string providerName)
        {
            _ConnectionString = connectionString;
            _ProviderFactory = DbProviderFactories.GetFactory(providerName);
        }
        /// <summary>
        /// 创建连接
        /// </summary>
        /// <returns></returns>
        private DbConnection CreateConnection()
        {
            var connection = _ProviderFactory.CreateConnection();
            connection.ConnectionString = _ConnectionString;
            connection.Open();
            return connection;
        }
        /// <summary>
        /// 执行SQL语句返回影响行数
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters"> 参数</param>
        /// <returns></returns>
        public int ExecuteNonQuery(string sql, object parameters)
        {
            using (var connection = CreateConnection())
            {
                using (var cmd = connection.CreateCommand())
                {
                    return new XCommand(cmd).ExecuteNonQuery(sql, parameters);
                }
            }
        }
        /// <summary>
        /// 执行SQL语句查询返回集合
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <param name="action">返回事件</param>
        /// <returns></returns>
        public IEnumerable<T> ExecuteDataReader<T>(string sql, object parameters, Func<DbDataReader, T> action)
        {
            using (var connection = CreateConnection())
            {
                using (var cmd = connection.CreateCommand())
                {
                    var db = new XCommand(cmd);
                    // 这里一定要用yield，这样可以延迟执行，直接用return db.ExecuteDataReader(sql, parameters, action)在执行dr.Read()的时候，cmd对象早就释放掉了
                    foreach (var r in db.ExecuteDataReader(sql, parameters, action))
                        yield return r;
                }
            }
        }
        /// <summary>
        /// 执行SQL语句查询返回集合
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <param name="action">返回集合事件</param>
        public void ExecuteDataReader(string sql, object parameters, Action<DbDataReader> action)
        {
            using (var connection = CreateConnection())
            {
                using (var cmd = connection.CreateCommand())
                {
                    var db = new XCommand(cmd);
                    db.ExecuteDataReader(sql, parameters, action);
                }
            }
        }
        /// <summary>
        /// 执行事务
        /// </summary>
        /// <param name="action">在事件中所有查询，修改，插入操作都在一个事务</param>
        public void ExecuteTransaction(Action<IDatabase> action)
        {
            using (var connection = CreateConnection())
            {
                using (var transaction = connection.BeginTransaction())
                {
                    try
                    {
                        using (var cmd = connection.CreateCommand())
                        {
                            cmd.Transaction = transaction;

                            var db = new XCommand(cmd);
                            db.ExecuteTransaction(action);
                        }

                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
        }
        /// <summary>
        /// 返回单个值
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public T ExecuteScalar<T>(string sql, object parameters)
        {
            using (var connection = CreateConnection())
            {
                using (var cmd = connection.CreateCommand())
                {
                    var db = new XCommand(cmd);
                    return db.ExecuteScalar<T>(sql, parameters);
                }
            }
        }
        /// <summary>
        /// 批量复制
        /// </summary>
        /// <param name="table">数据表</param>
        /// <param name="batchSize">每次复制条数</param>
        public void BulkCopy(DataTable table, int batchSize)
        {
            using (var connection = CreateConnection())
            {
                using (var cmd = connection.CreateCommand())
                {
                    var db = new XCommand(cmd);
                    db.BulkCopy(table, batchSize);
                }
            }
        }
        /// <summary>
        /// 判断是否存在行
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public bool HasRow(string sql, object parameters)
        {
            using (var connection = CreateConnection())
            {
                using (var cmd = connection.CreateCommand())
                {
                    var db = new XCommand(cmd);
                    return db.HasRow(sql, parameters);
                }
            }
        }
        /// <summary>
        /// 数据库链接
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return _ConnectionString;
        }
    }
}
